package com.ecp.commons.db;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.ecp.commons.bean.Page;
import com.ecp.commons.dao.IDSMongo;
import com.ecp.commons.serialization.MongoBean;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;

public class MongoDAOImpl2<T extends MongoBean> {
	protected DB		db				= null;
	protected T			t				= null;
	private String		collectionName	= "";

	private IDSMongo	idsMongo		= null;

	public MongoDAOImpl2() {
		Type genType = this.getClass().getGenericSuperclass();
		if (genType instanceof ParameterizedType) {
			@SuppressWarnings("unchecked")
			Class<T> cls = (Class<T>) ((ParameterizedType) genType).getActualTypeArguments()[0];
			try {
				t = cls.newInstance();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		collectionName = t.getCollectionName();
	}

	@Resource(name = "mongodb")
	public void setDB(MongoDB mongodb) {
		db = mongodb.getMongoDB();
	}

	@Resource(name = "idsMongo")
	public void setIdsDAO(IDSMongo idsMongo) {
		this.idsMongo = idsMongo;
	}

	protected DBCollection getCollection() {
		DBCollection coll = db.getCollection(collectionName);
		coll.setObjectClass(t.getClass());
		return coll;
	}

	@SuppressWarnings("unchecked")
	public T load(long id) {
		return (T) this.getCollection().findOne(new BasicDBObject("_id", id));
	}

	@SuppressWarnings("unchecked")
	public T findAndModify(DBObject query, DBObject update) {
		return (T) this.getCollection().findAndModify(query, update);
	}

	//@Override
	public long add(T obj) throws Exception {
		if (obj.getId() == 0) {
			obj.setId(idsMongo.generateId(collectionName));
		}
		this.getCollection().insert(obj);
		return obj.getId();
	}

	//@Override
	public void delete(long id) {
		this.getCollection().remove(new BasicDBObject("_id", id));
	}

	//@Override
	public void update(T obj) {
		this.save(obj);
	}

	public void save(T obj) {
		this.getCollection().save(obj);
	}

	// 直接用load加save更合适
	public void updateField(long id, Map<String, Object> map) {
		BasicDBObject obj = new BasicDBObject(map);
		this.getCollection().update(new BasicDBObject("_id", id), new BasicDBObject("$set", obj));
	}

	//@Override
	@SuppressWarnings("unchecked")
	public T getEntity(Map<String, Object> condition) {
		return (T) this.getCollection().findOne(new BasicDBObject(condition));
	}

	//@Override
	@SuppressWarnings("unchecked")
	public List<T> getEntityList(Map<String, Object> condition, DBObject orderBy, Page page) {
		BasicDBObject query = new BasicDBObject(condition);
		DBCollection coll = this.getCollection();
		DBCursor cursor = coll.find(query);
		if (orderBy != null) {
			cursor.sort(orderBy);
		}
		if (page != null) {
			page.setTotalCount((int) coll.count(query));
			cursor.skip(page.getStart()).limit(page.getPageSize());
		}
		
		//return (List<T>) cursor.toArray();
		List<T> list = new ArrayList<T>();
		while (cursor.hasNext()) {
			list.add((T) cursor.next());
		}
		return list;
	}

	//@Override
	public JSONObject toJSON(T t, String[] keys) {
		JSONObject jobj = new JSONObject();
		try {
			if (keys == null) {
				for (String key : t.keySet()) {
					jobj.put(key, t.get(key));
				}
			} else {
				for (String key : keys) {
					if (t.keySet().contains(key)) {
						jobj.put(key, t.get(key));
					}
				}
			}
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return jobj;
	}

	//@Override
	public JSONArray toJSONArray(List<T> list, String keys[]) {
		JSONArray jarr = new JSONArray();
		for (T t : list) {
			jarr.put(this.toJSON(t, keys));
		}
		return jarr;
	}
}
